use core::{cell::RefCell, ptr::null};

use alloc::sync::Arc;

use crate::{irq::*, println, thread::*};

static mut RT_CURRENT_THREAD: *const RefCell<Thread> = null();

pub fn print_cur_thread() {
    unsafe{
        Arc::increment_strong_count(RT_CURRENT_THREAD);
        println!("{:#?}", Arc::from_raw(RT_CURRENT_THREAD));
    }
}

/// 改变当前线程，
/// 判断null是为了drop Arc的引用计数。
fn set_cur_thread(t: Arc<RefCell<Thread>>) {
    unsafe {
        let level = rt_hw_interrupt_disable();
        
        if !RT_CURRENT_THREAD.is_null() {
            Arc::decrement_strong_count(RT_CURRENT_THREAD);
        } 
        t.borrow_mut().running();
        RT_CURRENT_THREAD = Arc::into_raw(t);
        
        rt_hw_interrupt_enable(level);
    }
}

pub fn drop_cur_thread() {
    unsafe {
        Arc::decrement_strong_count(RT_CURRENT_THREAD);
        RT_CURRENT_THREAD = null();        
    }
}

pub fn get_cur_thread() -> Option<Arc<RefCell<Thread>>> {
    unsafe {
        if RT_CURRENT_THREAD.is_null() {
            return None;
        }
        let a = Arc::from_raw(RT_CURRENT_THREAD);
        Arc::increment_strong_count(RT_CURRENT_THREAD);

        Some(a)
    }
}

fn highest_prio() -> Option<usize> {
    for i in 0..RT_THREAD_PRIORITY_MAX {
        unsafe {
            if RT_THREAD_PRIORITY_TABLE[i].len() > 0 {
                return Some(i);
            }
        }
    }
    None
}


extern "C" {
    /// void rt_hw_context_switch_to(rt_ubase_t to);
    pub fn rt_hw_context_switch_to(to: usize);
    
    /// void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
    pub fn rt_hw_context_switch(from: usize, to: usize);

    /// void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
    pub fn rt_hw_context_switch_interrupt(from: usize, to: usize);
}

#[no_mangle]
pub extern "C" fn rt_sys_scheduler_start() {    
    for pri in 0..RT_THREAD_PRIORITY_MAX {
        if let Some(t) = pop_prio_thread(pri) {
            unsafe{
                //println!("will to thread = {:#x?}", t);
                let psaddr:*const usize = t.borrow_mut().sp_ptr();
                set_cur_thread(t);
                rt_hw_context_switch_to(psaddr as usize)
            }
        };
    }
}

#[no_mangle]
pub extern "C" fn rt_schedule() {
    let level = unsafe { rt_hw_interrupt_disable() };
    if let Some(cur) = get_cur_thread() {
        let mut flag_change = true;

        //print_thread_table(); // 查看优先级表

        if let Some(h) = highest_prio() {  
            
            let cur_pri = cur.borrow().priority();
            let cur_sp = cur.borrow().sp_ptr();
            if cur.borrow().is_running() && cur_pri < h {
                flag_change = false;
            }

            if flag_change {
                let to_thread = pop_prio_thread(h).unwrap();
                if cur.borrow().is_running() {
                    push_prio_table(cur);
                } else {
                    drop(cur);
                }
                let sp_to: *const usize = to_thread.borrow_mut().sp_ptr();
                set_cur_thread(to_thread);
                let sp_from: *const usize = cur_sp;
                unsafe {
                    let nest = get_interrupt_nest(); // 中断判断
                    if nest == 0 {
                        rt_hw_context_switch(sp_from as usize, sp_to as usize);
                    } else {
                        rt_hw_context_switch_interrupt(sp_from as usize, sp_to as usize);
                    }
                    
                }
            }
        }
    }

    unsafe { rt_hw_interrupt_enable(level); }
}